Option Explicit

'################################################################
' Descriptor
' 分离式 sql entity 管理器接口
' 分离内容:
'      entity 信息单独在一个 sheet 中保管
'       各entity item 信息单独在一个 sheet 中保管
'################################################################

Implements ISqlEntityManager

' entity 名称类型: 未知
Private Const ENTITY_NAME_TYPE_UNKONW As Integer = 1
' entity 名称类型: 逻辑名
Private Const ENTITY_NAME_TYPE_LOGIC As Integer = 2
' entity 名称类型: 物理名
Private Const ENTITY_NAME_TYPE_PHY As Integer = 3

'################################################################
' Field
'################################################################
'------------------------------
' entity
'------------------------------
' entity 信息管理 sheet 对象
Private fieldEntitySheet As Worksheet

' entity 信息的起始行号
Private fieldEntityInfoStartRow As Long

' 保存 entity 的物理名的列索引
' 从 1 开始
' 如果 sheet 内没有 entity 物理名，将会设置为 -1
Private fieldEntityPhyNameCol As Integer

' 保存 entity 的逻辑名的列索引
' 从 1 开始
' 如果 sheet 内没有 entity 逻辑名，将会设置为 -1
Private fieldEntityLogicNameCol As Integer

'------------------------------
' entity item
'------------------------------
' item 信息管理 sheet 对象
Private fieldItemSheet As Worksheet

' item 信息的起始行号
Private fieldItemInfoStartRow As Long

' 保存 item 的物理名的列索引
' 从 1 开始
' 如果 sheet 内没有 item 物理名，将会设置为 -1
Private fieldItemPhyNameCol As Integer

' 保存 item 的逻辑名的列索引
' 从 1 开始
' 如果 sheet 内没有 item 逻辑名，将会设置为 -1
Private fieldItemLogicNameCol As Integer

' 保存 item 所在的 entity 的逻辑名的列索引
' 从 1 开始
' 如果 sheet 内没有 item 所在的 entity 的逻辑名，将会设置为 -1
Private fieldItemEntityLogicNameCol As Integer

' 保存 item 所在的 entity 的物理名的列索引
' 从 1 开始
' 如果 sheet 内没有 item 所在的 entity 的物理名，将会设置为 -1
Private fieldItemEntityPhyNameCol As Integer

'------------------------------
' cache
'------------------------------
' entity 信息管理 sheet 的最后一行
Private entitySheetLastRowNo As Long

' item 信息管理 sheet 的最后一行
Private itemSheetLastRowNo As Long

'################################################################
' Init
'################################################################
' @param entitySheet entity 信息管理 sheet 对象
' @param itemSheet item 信息管理 sheet 对象
' @optional-param entityInfoStartRow entity 信息的起始行号
'                                    必须是一个大于 0 的数值
'                                    如果提供了一个小于等于 0 的数，将会自动设置为 1
' @optional-param entityLogicNameCol entity 的逻辑名的列索引或列名，默认 = -1
'                                    从 1 开始
'                                    如果 sheet 内没有 entity 逻辑名，应该设置为 -1 或一个负数
' @optional-param entityPhyNameCol entity 的物理名的列索引或列名，默认 = -1
'                                  从 1 开始
'                                  如果 sheet 内没有 entity 物理名，应该设置为 -1 或一个负数
' @optional-param itemInfoStartRow item 信息的起始行号
'                                   必须是一个大于 0 的数值
'                                    如果提供了一个小于等于 0 的数，将会自动设置为 1
' @optional-param itemPhyNameCol 保存 item 的物理名的列索引或列名，默认 = -1
'                                从 1 开始
'                                如果 sheet 内没有 item 物理名，应该设置为 -1 或一个负数
' @optional-param itemLogicNameCol 保存 item 的逻辑名的列索引或列名，默认 = -1
'                                   从 1 开始
'                                   如果 sheet 内没有 item 逻辑名，应该设置为 -1 或一个负数
' @optional-param itemEntityLogicNameCol 保存 item 所在的 entity 的逻辑名的列索引或列名，默认 = -1
'                                        从 1 开始
'                                        如果 sheet 内没有 item 所在的 entity 的逻辑名，应该设置为 -1 或一个负数
' @optional-param itemEntityPhyNameCol 保存 item 所在的 entity 的物理名的列索引或列名，默认 = -1
'                                      从 1 开始
'                                       如果 sheet 内没有 item 所在的 entity 的物理名，应该设置为 -1 或一个负数
Public Sub Init( _
    ByRef entitySheet As Worksheet, _
    ByRef itemSheet As Worksheet, _
    Optional ByRef entityInfoStartRow As Long = 1, _
    Optional ByRef entityLogicNameCol As Variant = -1, _
    Optional ByRef entityPhyNameCol As Variant = -1, _
    Optional ByRef itemInfoStartRow As Long = 1, _
    Optional ByRef itemPhyNameCol As Variant = -1, _
    Optional ByRef itemLogicNameCol As Variant = -1, _
    Optional ByRef itemEntityLogicNameCol As Variant = -1, _
    Optional ByRef itemEntityPhyNameCol As Variant = -1 _
    )

    ' 1. 检查参数
    If entitySheet Is Nothing Then
        Err.Raise 10001, Description:="parameter entitySheet must be not nothing"
    End If

    If itemSheet Is Nothing Then
        Err.Raise 10001, Description:="parameter itemSheet must be not nothing"
    End If

    ' 保存 sheet 对象
    Set fieldEntitySheet = entitySheet
    Set fieldItemSheet = itemSheet

    ' entityInfoStartRow entity 信息的起始行号
    ' 必须是一个大于 0 的数值
    ' 如果提供了一个小于等于 0 的数，将会自动设置为 1
    If entityInfoStartRow <= 0 Then
        fieldEntityInfoStartRow = 1
    Else
        fieldEntityInfoStartRow = entityInfoStartRow
    End If

    ' entityLogicNameCol entity 的逻辑名的列索引或列名
    If VarType(entityLogicNameCol) = vbString Then
        fieldEntityLogicNameCol = UtilsWorksheet.colStr2No(entityLogicNameCol & "")
    ElseIf IsNumeric(entityLogicNameCol) Then
        If entityLogicNameCol <= 0 Then
            fieldEntityLogicNameCol = -1
        Else
            fieldEntityLogicNameCol = Int(entityLogicNameCol)
        End If
    Else
        Err.Raise 10012, Description:="please user Integer Or String for param[entityLogicNameCol]."
    End If

    ' entityPhyNameCol entity 的物理名的列索引
    If VarType(entityPhyNameCol) = vbString Then
        fieldEntityPhyNameCol = UtilsWorksheet.colStr2No(entityPhyNameCol & "")
    ElseIf IsNumeric(entityPhyNameCol) Then
        If entityPhyNameCol <= 0 Then
            fieldEntityPhyNameCol = -1
        Else
            fieldEntityPhyNameCol = Int(entityPhyNameCol)
        End If
    Else
        Err.Raise 10012, Description:="please user Integer Or String for param[entityPhyNameCol]."
    End If

    ' itemInfoStartRow item 信息的起始行号
    ' 必须是一个大于 0 的数值
    ' 如果提供了一个小于等于 0 的数，将会自动设置为 1
    If itemInfoStartRow <= 0 Then
        fieldItemInfoStartRow = -1
    Else
        ' 赋值时，行号 - 1，以防止第一行中的数据无法被找到！！！！！
        fieldItemInfoStartRow = itemInfoStartRow - 1
        if fieldItemInfoStartRow = 0 Then
            fieldItemInfoStartRow = 1
        End If
    End If

    ' itemPhyNameCol 保存 item 的物理名的列索引
    If VarType(itemPhyNameCol) = vbString Then
        fieldItemPhyNameCol = UtilsWorksheet.colStr2No(itemPhyNameCol & "")
    ElseIf IsNumeric(itemPhyNameCol) Then
        If itemPhyNameCol <= 0 Then
            fieldItemPhyNameCol = -1
        Else
            fieldItemPhyNameCol = Int(itemPhyNameCol)
        End If
    Else
        Err.Raise 10012, Description:="please user Integer Or String for param[itemPhyNameCol]."
    End If

    ' itemLogicNameCol 保存 item 的逻辑名的列索引
    If VarType(itemLogicNameCol) = vbString Then
        fieldItemLogicNameCol = UtilsWorksheet.colStr2No(itemLogicNameCol & "")
    ElseIf IsNumeric(itemLogicNameCol) Then
        If itemLogicNameCol <= 0 Then
            fieldItemLogicNameCol = -1
        Else
            fieldItemLogicNameCol = Int(itemLogicNameCol)
        End If
    Else
        Err.Raise 10012, Description:="please user Integer Or String for param[itemLogicNameCol]."
    End If

    ' itemEntityLogicNameCol 保存 item 所在的 entity 的逻辑名的列索引
    If VarType(itemEntityLogicNameCol) = vbString Then
        fieldItemEntityLogicNameCol = UtilsWorksheet.colStr2No(itemEntityLogicNameCol & "")
    ElseIf IsNumeric(itemEntityLogicNameCol) Then
        If itemEntityLogicNameCol <= 0 Then
            fieldItemEntityLogicNameCol = -1
        Else
            fieldItemEntityLogicNameCol = Int(itemEntityLogicNameCol)
        End If
    Else
        Err.Raise 10012, Description:="please user Integer Or String for param[itemEntityLogicNameCol]."
    End If

    ' itemEntityPhyNameCol 保存 item 所在的 entity 的物理名的列索引
    If VarType(itemEntityPhyNameCol) = vbString Then
        fieldItemEntityPhyNameCol = UtilsWorksheet.colStr2No(itemEntityPhyNameCol & "")
    ElseIf IsNumeric(itemEntityPhyNameCol) Then
        If itemEntityPhyNameCol <= 0 Then
            fieldItemEntityPhyNameCol = -1
        Else
            fieldItemEntityPhyNameCol = Int(itemEntityPhyNameCol)
        End If
    Else
        Err.Raise 10012, Description:="please user Integer Or String for param[itemEntityPhyNameCol]."
    End If

    ' 获取各个 sheet 的最后一行行号
    entitySheetLastRowNo = fieldEntitySheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
    itemSheetLastRowNo = fieldItemSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row

End Sub

'################################################################
' Function
'################################################################
'----------------------------------------------------------------
' entity 名转换
'----------------------------------------------------------------
' 使用 entity 的物理名来获取 entity 的逻辑名
' @param phyName entity 的物理名
Public Function ISqlEntityManager_getEntityLogicName(ByRef phyName As String) As String
    ' 1. 检查参数
    ' 1.1 如果参数是空字符串，则直接返回一个空字符串
    If phyName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2 如果 entity 逻辑名列索引不可用，则立刻停止
    ' 1.3 如果 entity 物理名列索引不可用，则立刻终止
    If fieldEntityLogicNameCol = -1 Or fieldEntityPhyNameCol = -1 Then
        ' return null
        Exit Function
    End If

    ' 2. 搜索参数名 phyName 所在的行数
    Dim phyNameRng As Range
    Set phyNameRng = findInEntitySheet(fieldEntityPhyNameCol, phyName)

    ' 如果搜索失败，则返回 ""
    If phyNameRng Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 3. 从 phyName 所在行上搜索逻辑名
    Dim logicNameRng As Range
    Set logicNameRng = fieldEntitySheet.Cells(phyNameRng.Row, fieldEntityLogicNameCol)
    If logicNameRng Is Nothing Then
        ISqlEntityManager_getEntityLogicName = ""
    Else
        ISqlEntityManager_getEntityLogicName = logicNameRng.Value
    End If
End Function

' 使用 entity 的逻辑名来获取 entity 的物理名
' @param phyName entity 的逻辑名
Public Function ISqlEntityManager_getEntityPhyName(ByRef logicName As String) As String
    ' 1. 检查参数
    ' 1.1 如果参数是空字符串，则直接返回一个空字符串
    If logicName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2 如果 entity 逻辑名列索引不可用，则立刻停止
    ' 1.3 如果 entity 物理名列索引不可用，则立刻终止
    If fieldEntityLogicNameCol = -1 Or fieldEntityPhyNameCol = -1 Then
        ISqlEntityManager_getEntityPhyName = ""
        Exit Function
    End If

    ' 2. 搜索参数名 logicName 所在的行数
    Dim logicNameRng As Range
    Set logicNameRng = findInEntitySheet(fieldEntityLogicNameCol, logicName)

    ' 如果搜索失败，则返回 ""
    If logicNameRng Is Nothing Then
        ISqlEntityManager_getEntityPhyName = ""
        Exit Function
    End If

    ' 3. 从 phyName 所在行上搜索物理名
    Dim phyNameRng As Range
    Set phyNameRng = fieldEntitySheet.Cells(logicNameRng.Row, fieldEntityPhyNameCol)
    If phyNameRng Is Nothing Then
        ISqlEntityManager_getEntityPhyName = ""
    Else
        ISqlEntityManager_getEntityPhyName = phyNameRng.Value
    End If
End Function

'----------------------------------------------------------------
' item 名转换
'----------------------------------------------------------------
' 使用 item 逻辑名，获取 item 物理名
'
' @param itemLogicName item 逻辑名
' @param entityName entity名
'                   可以是逻辑名，可以是物理名，需要各实现类提供判断的实现
Public Function ISqlEntityManager_getItemPhyName(ByRef itemLogicName As String, ByRef entityName As String) As String
    ' 1. 检查参数
    '    如果任意一个参数是空字符串，则返回 ""
    If itemLogicName = "" Then
        ' return ""
        Exit Function
    End If
    If entityName = "" Then
        ' return ""
        Exit Function
    End If

    ' 2. 确认 entityName 的类型
    Dim entityNameType As Integer
    entityNameType = getEntityNameType(entityName)

    ' 如果是未知类型，则立刻结束
    If entityNameType = ENTITY_NAME_TYPE_UNKONW Then
        ' return ""
        Exit Function
    End If

    If entityNameType = ENTITY_NAME_TYPE_LOGIC Then
        ' 使用 entity 逻辑名 + item 逻辑名的方式搜索 item 物理名
        ISqlEntityManager_getItemPhyName = _
            ISqlEntityManager_getItemPhyNameByEntityLogicName(itemLogicName, entityName)
    Else
        ' 使用 entity 物理名 + item 逻辑名的方式搜索 item 物理名
        ISqlEntityManager_getItemPhyName = _
            ISqlEntityManager_getItemPhyNameByEntityPhyName(itemLogicName, entityName)
    End If
End Function

' 使用 item 逻辑名 + entity 物理名，获取 item 物理名
'
' @param itemLogicName item 逻辑名
' @param entityPhyName entity物理名
Public Function ISqlEntityManager_getItemPhyNameByEntityPhyName(ByRef itemLogicName As String, ByRef entityPhyName As String) As String
    ' 1. 检查参数
    ' 1.1 如果任意一个参数是空字符串，则返回 ""
    If itemLogicName = "" Then
        ' return ""
        Exit Function
    End If
    If entityPhyName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2   如果 item sheet 中没有列的逻辑名，则停止检查
    '       如果 item sheet 中没有列的物理名，则停止检查
    If fieldItemLogicNameCol = -1 Or fieldItemPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 1.3 如果 item sheet 中没有 entity 物理名，也没有 entity 逻辑名，则停止检查
    If fieldItemEntityLogicNameCol = -1 And fieldItemEntityPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityPhyName(entityPhyName)
    If entityTargetName = "" Then
        ' return ""
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityPhyName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return ""
        Exit Function
    End If

    ' 3. 使用 entity 目标名 + item 逻辑名在 item sheet 中进行搜索
    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 目标名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 遍历行的时候，检查各行的 item 逻辑名，如果和参数值相同，则返回这一行上的 item 物理名
            If .Cells(i, fieldItemLogicNameCol).Value = itemLogicName Then
                ISqlEntityManager_getItemPhyNameByEntityPhyName = .Cells(i, fieldItemPhyNameCol).Value
                Exit Function
            End If
        Next
    End With

    ' 到这里说明没有找到匹配的结果，返回空字符串
    ISqlEntityManager_getItemPhyNameByEntityPhyName = ""
End Function

' 使用 item 逻辑名 + entity 逻辑名，获取 item 物理名
'
' @param itemLogicName item 逻辑名
' @param entityLogicName entity逻辑名
Public Function ISqlEntityManager_getItemPhyNameByEntityLogicName(ByRef itemLogicName As String, ByRef entityLogicName As String) As String
    ' 1. 检查参数
    ' 1.1 如果任意一个参数是空字符串，则返回 ""
    If itemLogicName = "" Then
        ' return ""
        Exit Function
    End If
    If entityLogicName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2   如果 item sheet 中没有列的逻辑名，则停止检查
    '       如果 item sheet 中没有列的物理名，则停止检查
    If fieldItemLogicNameCol = -1 Or fieldItemPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 1.3 如果 item sheet 中没有 entity 物理名，也没有 entity 逻辑名，则停止检查
    If fieldItemEntityLogicNameCol = -1 And fieldItemEntityPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityLogicName(entityLogicName)
    If entityTargetName = "" Then
        ' return ""
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityLogicName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return ""
        Exit Function
    End If

    ' 3. 使用 entity 目标名 + item 逻辑名在 item sheet 中进行搜索
    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 遍历行的时候，检查各行的 item 逻辑名，如果和参数值相同，则返回这一行上的 item 物理名
            If .Cells(i, fieldItemLogicNameCol).Value = itemLogicName Then
                ISqlEntityManager_getItemPhyNameByEntityLogicName = .Cells(i, fieldItemPhyNameCol).Value
                Exit Function
            End If
        Next
    End With

    ' 到这里说明没有找到匹配的结果，返回空字符串
    ISqlEntityManager_getItemPhyNameByEntityLogicName = ""
End Function

' 使用 item 物理名获取 item 逻辑名
'
' @param itemLogicName item 物理名
' @param entityName entity名
'                   可以是逻辑名，可以是物理名，需要各实现类提供判断的实现
Public Function ISqlEntityManager_getItemLogicName(ByRef itemPhyName As String, ByRef entityName As String) As String
    ' 1. 确认 entityName 的类型
    Dim entityNameType As Integer
    entityNameType = getEntityNameType(entityName)

    ' 如果是未知类型，则立刻结束
    If entityNameType = ENTITY_NAME_TYPE_UNKONW Then
        ' return ""
        Exit Function
    End If

    If entityNameType = ENTITY_NAME_TYPE_LOGIC Then
        ' 使用 entity 逻辑名 + item 物理名的方式搜索 item 逻辑名
        ISqlEntityManager_getItemLogicName = _
            ISqlEntityManager_getItemLogicNameByEntityLogicName(itemPhyName, entityName)
    Else
        ' 使用 entity 物理名 + item 物理名的方式搜索 item 逻辑名
        ISqlEntityManager_getItemLogicName = _
            ISqlEntityManager_getItemLogicNameByEntityPhyName(itemPhyName, entityName)
    End If
End Function

' 使用 item 物理名 + entity 物理名，获取 item 逻辑名
'
' 如果无法找到，则返回 ""
'
' @param itemPhyName item 物理名
' @param entityPhyName entity物理名
Public Function ISqlEntityManager_getItemLogicNameByEntityPhyName(ByRef itemPhyName As String, ByRef entityPhyName As String) As String
    ' 1. 检查参数
    ' 1.1 如果任意一个参数是空字符串，则返回 ""
    If itemPhyName = "" Then
        ' return ""
        Exit Function
    End If
    If entityPhyName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2   如果 item sheet 中没有列的逻辑名，则停止检查
    '       如果 item sheet 中没有列的物理名，则停止检查
    If fieldItemLogicNameCol = -1 Or fieldItemPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 1.3 如果 item sheet 中没有 entity 物理名，也没有 entity 逻辑名，则停止检查
    If fieldItemEntityLogicNameCol = -1 And fieldItemEntityPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityPhyName(entityPhyName)
    If entityTargetName = "" Then
        ' return ""
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityPhyName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return ""
        Exit Function
    End If

    ' 3. 使用 entity 目标名 + item 逻辑名在 item sheet 中进行搜索
    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 目标名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 遍历行的时候，检查各行的 item 物理名，如果和参数值相同，则返回这一行上的 item 逻辑名
            If .Cells(i, fieldItemPhyNameCol).Value = itemPhyName Then
                ISqlEntityManager_getItemLogicNameByEntityPhyName = .Cells(i, fieldItemLogicNameCol).Value
                Exit Function
            End If
        Next
    End With

    ' 到这里说明没有找到匹配的结果，返回空字符串
    ISqlEntityManager_getItemLogicNameByEntityPhyName = ""
End Function

' 使用 item 物理名 + entity 逻辑名，获取 item 逻辑名
'
' 如果无法找到，则返回 ""
'
' @param itemPhyName item 物理名
' @param entityLogicName entity逻辑名
Public Function ISqlEntityManager_getItemLogicNameByEntityLogicName(ByRef itemPhyName As String, ByRef entityLogicName As String) As String
    ' 1. 检查参数
    ' 1.1 如果任意一个参数是空字符串，则返回 ""
    If itemPhyName = "" Then
        ' return ""
        Exit Function
    End If
    If entityLogicName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2   如果 item sheet 中没有列的逻辑名，则停止检查
    '       如果 item sheet 中没有列的物理名，则停止检查
    If fieldItemLogicNameCol = -1 Or fieldItemPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 1.3 如果 item sheet 中没有 entity 物理名，也没有 entity 逻辑名，则停止检查
    If fieldItemEntityLogicNameCol = -1 And fieldItemEntityPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityLogicName(entityLogicName)
    If entityTargetName = "" Then
        ' return ""
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityLogicName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return ""
        Exit Function
    End If

    ' 3. 使用 entity 目标名 + item 逻辑名在 item sheet 中进行搜索
    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 遍历行的时候，检查各行的 item 物理名，如果和参数值相同，则返回这一行上的 item 逻辑名
            If .Cells(i, fieldItemPhyNameCol).Value = itemPhyName Then
                ISqlEntityManager_getItemLogicNameByEntityLogicName = .Cells(i, fieldItemLogicNameCol).Value
                Exit Function
            End If
        Next
    End With

    ' 到这里说明没有找到匹配的结果，返回空字符串
    ISqlEntityManager_getItemLogicNameByEntityLogicName = ""
End Function

'----------------------------------------------------------------
' 检查 item 名的类型
'----------------------------------------------------------------
' 检查当前的 item 是不是逻辑名
'
' @param itemName, 需要检查的 item 名称
' @param entityLogicName, entity逻辑名
Public Function ISqlEntityManager_isLogicItemNameByEntityLogicName(ByRef itemName As String, ByRef entityLogicName As String) As Boolean
    ' 1. 检查参数
    ' 1.1 如果任意一个参数是空字符串，则返回 ""
    If itemName = "" Then
        ' return ""
        Exit Function
    End If
    If entityLogicName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2   如果 item sheet 中没有列的逻辑名，则停止检查
    If fieldItemLogicNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 1.3 如果 item sheet 中没有 entity 物理名，也没有 entity 逻辑名，则停止检查
    If fieldItemEntityLogicNameCol = -1 And fieldItemEntityPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityLogicName(entityLogicName)
    If entityTargetName = "" Then
        ' return ""
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityLogicName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return ""
        Exit Function
    End If

    ' 3. 使用 entity 目标名，检查参数 itemName 是不是逻辑名
    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 遍历行的时候，检查各行的 item 逻辑名，如果和参数值相同，则返回这一行上的 item 物理名
            If .Cells(i, fieldItemLogicNameCol).Value = itemName Then
                ISqlEntityManager_isLogicItemNameByEntityLogicName = True
                Exit Function
            End If
        Next
    End With

    ' 到这里说明参数不是逻辑名
    ISqlEntityManager_isLogicItemNameByEntityLogicName = False
End Function

' 检查当前的 item 是不是物理名
'
' @param itemName, 需要检查的 item 名称
' @param entityPhyName, entity物理名
Public Function ISqlEntityManager_isPhyItemNameByEntityPhyName(ByRef itemName As String, ByRef entityPhyName As String) As Boolean
    ' 1. 检查参数
    ' 1.1 如果任意一个参数是空字符串，则返回 ""
    If itemName = "" Then
        ' return ""
        Exit Function
    End If
    If entityPhyName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2   如果 item sheet 中没有列的物理名，则停止检查
    If fieldItemPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 1.3 如果 item sheet 中没有 entity 物理名，也没有 entity 逻辑名，则停止检查
    If fieldItemEntityLogicNameCol = -1 And fieldItemEntityPhyNameCol = -1 Then
        ' return ""
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityPhyName(entityPhyName)
    If entityTargetName = "" Then
        ' return ""
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityPhyName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return ""
        Exit Function
    End If

    ' 3. 使用 entity 目标名，检查参数 itemName 是不是物理名
    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 遍历行的时候，检查各行的 item 物理名，如果和参数值相同，则返回这一行上的 item 逻辑名
            If .Cells(i, fieldItemPhyNameCol).Value = itemName Then
                ISqlEntityManager_isPhyItemNameByEntityPhyName = True
                Exit Function
            End If
        Next
    End With

    ' 到这里说明参数不是物理名
    ISqlEntityManager_isPhyItemNameByEntityPhyName = False
End Function

'----------------------------------------------------------------
' 获取名称映射
'----------------------------------------------------------------
' 返回指定 entity 下的所有 item 物理名
'
' 如果没有找到 entity ，则返回 `Nothing`
' 如果完全没有 `物理 item 名`，则返回 `Nothing`
'
' @param entityName entity 名称
Public Function ISqlEntityManager_getItemPhyNames(ByRef entityName As String) As IPrimitiveArrayRef
    ' 1. 检查参数
    ' 1.1 如果完全没有 `物理 item 名`，则返回 `Nothing`
    If fieldItemPhyNameCol = -1 Then
        ' return null
        Exit Function
    End If

    '  1.2 如果任意一个参数是空字符串，则返回 ""
    If entityName = "" Then
        ' return null
        Exit Function
    End If

    ' 2. 确认 entityName 的类型
    Dim entityNameType As Integer
    entityNameType = getEntityNameType(entityName)

    ' 如果是未知类型，则立刻结束
    If entityNameType = ENTITY_NAME_TYPE_UNKONW Then
        ' return null
        Exit Function
    End If

    ' 获取所有 item 物理名
    If entityNameType = ENTITY_NAME_TYPE_LOGIC Then
        ' 使用 entity 逻辑名 搜索映射
        Set ISqlEntityManager_getItemPhyNames = getItemPhyNamesByEntityLogicName(entityName)
    Else
        ' 使用 entity 物理名 搜索映射
        Set ISqlEntityManager_getItemPhyNames = getItemPhyNamesByEntityPhyName(entityName)
    End If
End Function

' 获取entity 下的所有 item 物理名
'
' @param entityLogicName 逻辑 entity 名
Private Function getItemPhyNamesByEntityLogicName(ByRef entityLogicName As String) As IPrimitiveArrayRef
    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityLogicName(entityLogicName)
    If entityTargetName = "" Then
        ' return null
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityLogicName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 3. 收集列名
    Set getItemPhyNamesByEntityLogicName = UtilsArrayRef.createRealPrimitiveArrayRef

    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 保存映射
            getItemPhyNamesByEntityLogicName.Add .Cells(i, fieldItemPhyNameCol).Value
        Next
    End With
End Function

' 获取entity 下的所有 item 物理名
'
' @param entityPhyName 物理 entity 名
Private Function getItemPhyNamesByEntityPhyName(ByRef entityPhyName As String) As Object
    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityPhyName(entityPhyName)
    If entityTargetName = "" Then
        ' return null
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityPhyName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 3. 收集名称
    Set getItemPhyNamesByEntityPhyName = UtilsArrayRef.createRealPrimitiveArrayRef

    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 保存映射
            getItemPhyNamesByEntityPhyName.Add .Cells(i, fieldItemPhyNameCol).Value
        Next
    End With
End Function


' 返回指定 entity 下的所有 item 逻辑名
'
' 如果没有找到 entity ，则返回 `Nothing`
' 如果完全没有 `逻辑 item 名`，则返回 `Nothing`
'
' @param entityName entity 名称
Public Function ISqlEntityManager_getItemLogicNames(ByRef entityName As String) As IPrimitiveArrayRef
    ' 1. 检查参数
    ' 1.1 如果完全没有 `逻辑 item 名`，则返回 `Nothing`
    If fieldItemLogicNameCol = -1 Then
        ' return null
        Exit Function
    End If

    '  1.2 如果任意一个参数是空字符串，则返回 ""
    If entityName = "" Then
        ' return null
        Exit Function
    End If

    ' 2. 确认 entityName 的类型
    Dim entityNameType As Integer
    entityNameType = getEntityNameType(entityName)

    ' 如果是未知类型，则立刻结束
    If entityNameType = ENTITY_NAME_TYPE_UNKONW Then
        ' return null
        Exit Function
    End If

    ' 获取所有 item 物理名
    If entityNameType = ENTITY_NAME_TYPE_LOGIC Then
        ' 使用 entity 逻辑名 搜索映射
        Set ISqlEntityManager_getItemLogicNames = getItemLogicNamesByEntityLogicName(entityName)
    Else
        ' 使用 entity 物理名 搜索映射
        Set ISqlEntityManager_getItemLogicNames = getItemLogicNamesByEntityPhyName(entityName)
    End If
End Function

' 获取entity 下的所有 item 逻辑名
'
' @param entityLogicName 逻辑 entity 名
Public Function getItemLogicNamesByEntityLogicName(ByRef entityLogicName As String) As IPrimitiveArrayRef
    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityLogicName(entityLogicName)
    If entityTargetName = "" Then
        ' return null
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityLogicName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 3. 收集名称
    Set getItemLogicNamesByEntityLogicName = UtilsArrayRef.createRealPrimitiveArrayRef

    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 保存映射
            getItemLogicNamesByEntityLogicName.Add .Cells(i, fieldItemLogicNameCol).Value
        Next
    End With
End Function

' 获取entity 下的所有 item 逻辑名
'
' @param entityPhyName 物理 entity 名
Public Function getItemLogicNamesByEntityPhyName(ByRef entityPhyName As String) As IPrimitiveArrayRef
    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityPhyName(entityPhyName)
    If entityTargetName = "" Then
        ' return ""
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityPhyName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 3. 收集名称
    Set getItemLogicNamesByEntityPhyName = UtilsArrayRef.createRealPrimitiveArrayRef

    With fieldItemSheet
        Dim i As Long
        For i = tempRng.Row To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 保存映射
            getItemLogicNamesByEntityPhyName.Add .Cells(i, fieldItemLogicNameCol).Value
        Next
    End With
End Function

'----------------------------------------------------------------
' 获取名称映射
'----------------------------------------------------------------
' 物理 item 名 --> 逻辑 item 名

' 自动判断 entity 名列名，并获取: `物理 item 名 --> 逻辑 item 名` 的映射
' 如果没有找到 entity ，则返回 Nothing
' 如果完全没有 物理 item 名，则返回 Nothing
' 如果某个 item 只有物理 item 名，没有逻辑 item 名，则保存映射为: 物理 item 名 --> ""
'
' @param entityName entity 名
' @return dictionary
Public Function ISqlEntityManager_getItemPhyLogicMap(ByRef entityName As String) As Object
    ' 1. 检查参数
    '    如果任意一个参数是空字符串，则返回 ""
    If entityName = "" Then
        ' return null
        Exit Function
    End If

    ' 2. 确认 entityName 的类型
    Dim entityNameType As Integer
    entityNameType = getEntityNameType(entityName)

    ' 如果是未知类型，则立刻结束
    If entityNameType = ENTITY_NAME_TYPE_UNKONW Then
        ' return null
        Exit Function
    End If

    If entityNameType = ENTITY_NAME_TYPE_LOGIC Then
        ' 使用 entity 逻辑名 搜索映射
        Set ISqlEntityManager_getItemPhyLogicMap = _
            ISqlEntityManager_getItemPhyLogicMapByEntityLogicName(entityName)
    Else
        ' 使用 entity 物理名 搜索映射
        Set ISqlEntityManager_getItemPhyLogicMap = _
            ISqlEntityManager_getItemPhyLogicMapByEntityPhyName(entityName)
    End If
End Function

' 使用逻辑 entity 名，获取: `物理 item 名 --> 逻辑 item 名` 的映射
' 如果没有找到 entity ，则返回 Nothing
' 如果完全没有 物理 item 名，则返回 Nothing
' 如果某个 item 只有物理 item 名，没有逻辑 item 名，则保存映射为: 物理 item 名 --> ""
'
' @param entityLogicName 逻辑 entity 名
' @return dictionary
Public Function ISqlEntityManager_getItemPhyLogicMapByEntityLogicName(ByRef entityLogicName As String) As Object
    ' 1. 检查参数
    '    如果 entity 名是空字符串，则返回 Nothing
    If entityLogicName = "" Then
        ' return null
        Exit Function
    End If

    ' 1.2 如果 Item sheet 没有物理 item 名，则返回 Nothing
    If fieldItemPhyNameCol = -1 Then
        ' return null
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityLogicName(entityLogicName)
    If entityTargetName = "" Then
        ' return null
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityLogicName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 3. 收集名称
    If fieldItemPhyNameCol = -1 Then
        ' 3.1 如果 Item sheet 没有逻辑 item 名，也创建一个映射
        ' 但是只保存: 物理 item 名 --> "" 的映射
        Set ISqlEntityManager_getItemPhyLogicMapByEntityLogicName = collectPhyItemNameEmptyStrMap( _
            entityTargetName, entityTargetNameCol, tempRng.Row)
    Else
        ' 3.2 收集映射: 物理 item 名 --> 逻辑 item 名
        Set ISqlEntityManager_getItemPhyLogicMapByEntityLogicName = collectPhyLogicItemNameMap( _
            entityTargetName, entityTargetNameCol, tempRng.Row)
    End If
End Function

' 使用物理 entity 名，获取: `物理 item 名 --> 逻辑 item 名` 的映射
' 如果没有找到 entity ，则返回 Nothing
' 如果完全没有 物理 item 名，则返回 Nothing
' 如果某个 item 只有物理 item 名，没有逻辑 item 名，则保存映射为: 物理 item 名 --> ""
'
' @param entityPhyName 物理 entity 名
' @return dictionary
Public Function ISqlEntityManager_getItemPhyLogicMapByEntityPhyName(ByRef entityPhyName As String) As Object
    ' 1. 检查参数
    '    如果 entity 名是空字符串，则返回 Nothing
    If entityPhyName = "" Then
        ' return null
        Exit Function
    End If

    ' 1.2 如果 Item sheet 没有物理 item 名，则返回 Nothing
    If fieldItemPhyNameCol = -1 Then
        ' return null
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityPhyName(entityPhyName)
    If entityTargetName = "" Then
        ' return null
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityPhyName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 3. 收集名称
    If fieldItemPhyNameCol = -1 Then
        ' 3.1 如果 Item sheet 没有逻辑 item 名，也创建一个映射
        ' 但是只保存: 物理 item 名 --> "" 的映射
        Set ISqlEntityManager_getItemPhyLogicMapByEntityPhyName = collectPhyItemNameEmptyStrMap( _
            entityTargetName, entityTargetNameCol, tempRng.Row)
    Else
        ' 3.2 收集映射: 物理 item 名 --> 逻辑 item 名
        Set ISqlEntityManager_getItemPhyLogicMapByEntityPhyName = collectPhyLogicItemNameMap( _
            entityTargetName, entityTargetNameCol, tempRng.Row)
    End If
End Function

'------------------------------------
' 逻辑 item 名 --> 物理 item 名

' 自动判断 entity 名列名，并获取: `逻辑 item 名 --> 物理 item 名` 的映射
' 如果没有找到 entity ，则返回 Nothing
' 如果完全没有 物理 item 名，则返回 Nothing
' 如果某个 item 只有逻辑 item 名，没有物理 item 名，则保存映射为: 物理 item 名 --> ""
'
' @param entityName entity 名
' @return dictionary
Public Function ISqlEntityManager_getItemLogicPhyMap(ByRef entityName As String) As Object
    ' 1. 检查参数
    '    如果任意一个参数是空字符串，则返回 ""
    If entityName = "" Then
        ' return null
        Exit Function
    End If

    ' 2. 确认 entityName 的类型
    Dim entityNameType As Integer
    entityNameType = getEntityNameType(entityName)

    ' 如果是未知类型，则立刻结束
    If entityNameType = ENTITY_NAME_TYPE_UNKONW Then
        ' return null
        Exit Function
    End If

    If entityNameType = ENTITY_NAME_TYPE_LOGIC Then
        ' 使用 entity 逻辑名 搜索映射
        Set ISqlEntityManager_getItemLogicPhyMap = _
            ISqlEntityManager_getItemLogicPhyMapByEntityLogicName(entityName)
    Else
        ' 使用 entity 物理名 搜索映射
        Set ISqlEntityManager_getItemLogicPhyMap = _
            ISqlEntityManager_getItemLogicPhyMapByEntityPhyName(entityName)
    End If
End Function

' 使用逻辑 entity 名，获取: `逻辑 item 名 --> 物理 item 名` 的映射
' 如果没有找到 entity ，则返回 Nothing
' 如果完全没有 逻辑 item 名，则返回 Nothing
' 如果某个 item 只有逻辑 item 名，没有物理 item 名，则保存映射为: 逻辑 item 名 --> ""
'
' @param entityLogicName 逻辑 entity 名
' @return dictionary
Public Function ISqlEntityManager_getItemLogicPhyMapByEntityLogicName(ByRef entityLogicName As String) As Object
    ' 1. 检查参数
    '    如果 entity 名是空字符串，则返回 Nothing
    If entityLogicName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2 如果 Item sheet 没有逻辑 item 名，则返回 Nothing
    If fieldItemLogicNameCol = -1 Then
        ' return null
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityLogicName(entityLogicName)
    If entityTargetName = "" Then
        ' return null
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityLogicName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 3. 收集名称
    If fieldItemLogicNameCol = -1 Then
        ' 3.1 如果 Item sheet 没有物理 item 名，也创建一个映射
        ' 但是只保存: 逻辑 item 名 --> "" 的映射
        Set ISqlEntityManager_getItemLogicPhyMapByEntityLogicName = collectLogicItemNameEmptyStrMap( _
            entityTargetName, entityTargetNameCol, tempRng.Row)
    Else
        ' 3.2 收集映射: 逻辑 item 名 --> 物理 item 名
        Set ISqlEntityManager_getItemLogicPhyMapByEntityLogicName = collectLogicPhyItemNameMap( _
            entityTargetName, entityTargetNameCol, tempRng.Row)
    End If
End Function

' 使用物理 entity 名，获取: `逻辑 item 名 --> 物理 item 名` 的映射
' 如果没有找到 entity ，则返回 Nothing
' 如果完全没有 逻辑 item 名，则返回 Nothing
' 如果某个 item 只有逻辑 item 名，没有物理 item 名，则保存映射为: 逻辑 item 名 --> ""
'
' @param entityPhyName 物理 entity 名
' @return dictionary
Public Function ISqlEntityManager_getItemLogicPhyMapByEntityPhyName(ByRef entityPhyName As String) As Object
    ' 1. 检查参数
    '    如果 entity 名是空字符串，则返回 Nothing
    If entityPhyName = "" Then
        ' return ""
        Exit Function
    End If

    ' 1.2 如果 Item sheet 没有逻辑 item 名，则返回 Nothing
    If fieldItemLogicNameCol = -1 Then
        ' return null
        Exit Function
    End If

    ' 2. 确定搜索的方式
    '    如果目标 entity 是 "" 则立刻停止
    Dim entityTargetName As String
    entityTargetName = getEntityTargetNameByEntityPhyName(entityPhyName)
    If entityTargetName = "" Then
        ' return ""
        Exit Function
    End If

    Dim entityTargetNameCol As Integer
    entityTargetNameCol = getEntityTargetNameColByEntityPhyName

    ' 2.2 在 item sheet 中搜索 entity 目标名的起始行号
    '     如果没有找到，则立刻终止
    Dim tempRng As Range
    Set tempRng = findInItemSheet(entityTargetNameCol, entityTargetName)
    If tempRng Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 3. 收集名称
    If fieldItemLogicNameCol = -1 Then
        ' 3.1 如果 Item sheet 没有物理 item 名，也创建一个映射
        ' 但是只保存: 逻辑 item 名 --> "" 的映射
        Set ISqlEntityManager_getItemLogicPhyMapByEntityPhyName = collectLogicItemNameEmptyStrMap( _
            entityTargetName, entityTargetNameCol, tempRng.Row)
    Else
        ' 3.2 收集映射: 逻辑 item 名 --> 物理 item 名
        Set ISqlEntityManager_getItemLogicPhyMapByEntityPhyName = collectLogicPhyItemNameMap( _
            entityTargetName, entityTargetNameCol, tempRng.Row)
    End If
End Function


'################################################################
' Private Function
'################################################################
' 在 entity sheet 的指定列中搜索和指定数据相同的单元格区域
Private Function findInEntitySheet(ByRef foundCol As Integer, ByRef targetVal As String) As Range
    Dim endCell As Range
    Set endCell = fieldEntitySheet.Cells(entitySheetLastRowNo, foundCol)

    Dim rng As Range
    Set rng = fieldEntitySheet.Range( _
        fieldEntitySheet.Cells(fieldItemInfoStartRow, foundCol), _
        endCell _
    ).Find( _
        targetVal, _
        lookat:=xlWhole, _
        SearchDirection:=xlNext, _
        LookIn:=xlValues, _
        SearchOrder:=xlByRows _
    )

    Set findInEntitySheet = rng
End Function

' 在 entity item sheet 的指定列中搜索和指定数据相同的单元格区域
Private Function findInItemSheet(ByRef foundCol As Integer, ByRef targetVal As String) As Range
    Dim endCell As Range
    Set endCell = fieldItemSheet.Cells(itemSheetLastRowNo, foundCol)

    Dim rng As Range
    Set rng = fieldItemSheet.Range( _
        fieldItemSheet.Cells(fieldItemInfoStartRow, foundCol), _
        endCell _
    ).Find( _
        targetVal, _
        lookat:=xlWhole, _
        SearchDirection:=xlNext, _
        LookIn:=xlValues, _
        SearchOrder:=xlByRows _
    )

    Set findInItemSheet = rng
End Function

' 检查参数 entityName 是哪种类型的 entity 名称
'
' @param entityName 需要检查的 entity 名称
' @return 以下三种常量
'         ENTITY_NAME_TYPE_UNKONW
'         ENTITY_NAME_TYPE_LOGIC
'         ENTITY_NAME_TYPE_PHY
Private Function getEntityNameType(ByRef entityName As String) As Integer
    Dim rng As Range

    ' 1. 尝试在 entity 逻辑名中搜索参数
    Set rng = findInEntitySheet(fieldEntityLogicNameCol, entityName)
    If Not rng Is Nothing Then
        getEntityNameType = ENTITY_NAME_TYPE_LOGIC
        Exit Function
    End If

    ' 2. 尝试在 entity 物理名中搜索参数
    Set rng = findInEntitySheet(fieldEntityPhyNameCol, entityName)
    If Not rng Is Nothing Then
        getEntityNameType = ENTITY_NAME_TYPE_PHY
        Exit Function
    End If

    ' 3. 如果两中类型都没有找到，则返回 unknow
    getEntityNameType = ENTITY_NAME_TYPE_UNKONW
End Function

' 在 item sheet 中收集映射: 物理 item 名称 --> ""
'
' @param entityTargetName 目标类型的 entity 名称
' @param entityTargetNameCol 目标类型的 entity 名称在 item sheet 中的列索引
' @param scanStarRow 收集的起始行号
Private Function collectPhyItemNameEmptyStrMap( _
    ByRef entityTargetName As String, ByRef entityTargetNameCol As String, _
    ByRef scanStarRow As Long) As Object

    Set collectPhyItemNameEmptyStrMap = UtilsCreateSysObj.createMap

    With fieldItemSheet
        Dim i As Long
        For i = scanStarRow To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 保存映射
            collectPhyItemNameEmptyStrMap.Add .Cells(i, fieldItemPhyNameCol).Value, ""
        Next
    End With
End Function

' 收集映射: 物理 item 名 --> 逻辑 item 名
'
' @param entityTargetName 目标类型的 entity 名称
' @param entityTargetNameCol 目标类型的 entity 名称在 item sheet 中的列索引
' @param scanStarRow 收集的起始行号
Private Function collectPhyLogicItemNameMap( _
    ByRef entityTargetName As String, ByRef entityTargetNameCol As String, _
    ByRef scanStarRow As Long) As Object

    Set collectPhyLogicItemNameMap = UtilsCreateSysObj.createMap

    With fieldItemSheet
        Dim i As Long
        For i = scanStarRow To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 保存映射
            collectPhyLogicItemNameMap.Add .Cells(i, fieldItemPhyNameCol).Value, .Cells(i, fieldItemLogicNameCol).Value
        Next
    End With
End Function

' 3.1 如果 Item sheet 没有物理 item 名，也创建一个映射
        ' 但是只保存: 逻辑 item 名 --> "" 的映射

' 在 item sheet 中收集映射: 逻辑 item 名称 --> ""
'
' @param entityTargetName 目标类型的 entity 名称
' @param entityTargetNameCol 目标类型的 entity 名称在 item sheet 中的列索引
' @param scanStarRow 收集的起始行号
Private Function collectLogicItemNameEmptyStrMap( _
    ByRef entityTargetName As String, ByRef entityTargetNameCol As Integer, _
    ByRef scanStarRow As Long) As Object

    Set collectLogicItemNameEmptyStrMap = UtilsCreateSysObj.createMap

    With fieldItemSheet
        Dim i As Long
        For i = scanStarRow To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 保存映射
            collectLogicItemNameEmptyStrMap.Add .Cells(i, fieldItemLogicNameCol).Value, ""
        Next
    End With
End Function

' 收集映射: 逻辑 item 名 --> 物理 item 名
Private Function collectLogicPhyItemNameMap( _
    ByRef entityTargetName As String, ByRef entityTargetNameCol As Integer, _
    ByRef scanStarRow As Long) As Object

    Set collectLogicPhyItemNameMap = UtilsCreateSysObj.createMap

    With fieldItemSheet
        Dim i As Long
        For i = scanStarRow To itemSheetLastRowNo
            ' 从起始行开始向下遍历每一行，直到遍历到单元格值不等于 entity 名的行为止
            If .Cells(i, entityTargetNameCol).Value <> entityTargetName Then
                Exit For
            End If

            ' 保存映射
            collectLogicPhyItemNameMap.Add .Cells(i, fieldItemLogicNameCol).Value, .Cells(i, fieldItemPhyNameCol).Value
        Next
    End With
End Function

'----------------------------------------------------
' 任意类型 entity ---> item sheet 中的目标 entity 名称
'----------------------------------------------------
' 通过 entity 物理名，获取 item sheet 中的目标 entity 名称
Private Function getEntityTargetNameByEntityPhyName(ByRef entityPhyName As String) As String
    If fieldItemEntityPhyNameCol <> -1 Then
        ' 如果 item sheet 中已经存在 entity 物理名，则直接使用物理名作为 entity 目标名
        getEntityTargetNameByEntityPhyName = entityPhyName
    ElseIf fieldItemEntityLogicNameCol <> -1 Then
        ' 如果 item sheet 中不存在 entity 物理名，则使用逻辑名作为 entity 目标名
        ' 这种情况下，需要在这里将 entity 物理名转换成 entity 逻辑名
        getEntityTargetNameByEntityPhyName = ISqlEntityManager_getEntityLogicName(entityPhyName)
    Else
        getEntityTargetNameByEntityPhyName = ""
    End If
End Function

' 通过 entity 逻辑名，获取 item sheet 中的目标 entity 名称
Private Function getEntityTargetNameByEntityLogicName(ByRef entityLogicName As String) As String
    If fieldItemEntityLogicNameCol <> -1 Then
        ' 如果 item sheet 中已经存在 entity 逻辑名，则直接使用逻辑名作为 entity 目标名
        getEntityTargetNameByEntityLogicName = entityLogicName
    ElseIf fieldItemEntityPhyNameCol <> -1 Then
        ' 如果 item sheet 中不存在 entity 逻辑名，则使用物理名作为 entity 目标名
        ' 这种情况下，需要在这里将 entity 逻辑名转换成 entity 物理名
        getEntityTargetNameByEntityLogicName = ISqlEntityManager_getEntityPhyName(entityLogicName)
    Else
        getEntityTargetNameByEntityLogicName = ""
    End If
End Function

' 通过 entity 物理名，获取 item sheet 中的目标 entity 名称所在的列索引
Private Function getEntityTargetNameColByEntityPhyName() As Integer
    If fieldItemEntityPhyNameCol <> -1 Then
        getEntityTargetNameColByEntityPhyName = fieldItemEntityPhyNameCol
    ElseIf fieldItemEntityLogicNameCol <> -1 Then
        getEntityTargetNameColByEntityPhyName = fieldItemEntityLogicNameCol
    Else
        getEntityTargetNameColByEntityPhyName = -1
    End If
End Function

' 通过 entity 逻辑名，获取 item sheet 中的目标 entity 名称所在的列索引
Private Function getEntityTargetNameColByEntityLogicName() As Integer
    If fieldItemEntityLogicNameCol <> -1 Then
        getEntityTargetNameColByEntityLogicName = fieldItemEntityLogicNameCol
    ElseIf fieldItemEntityPhyNameCol <> -1 Then
        getEntityTargetNameColByEntityLogicName = fieldItemEntityPhyNameCol
    Else
        getEntityTargetNameColByEntityLogicName = -1
    End If
End Function